#include "serial.h"

USE_LOGGER(DEV);

static serial_configure _default_config = SERIAL_DEFAULT_CONFIG;
static uint16_t _rev_buf_size = 0;
static uint8_t *_rev_buf = NULL;
static rs485_mode _rs485 = NULL;
static int _revbuf_init(uint16_t size)
{
    if(size == 0)
        return -3;
    if(_rev_buf != NULL)
    {
        system_free(_rev_buf);
    }
    _rev_buf = (uint8_t *)system_malloc(size);
    if(_rev_buf == NULL)
        return -1;
    _rev_buf_size = size;
    return 1;
}

static int _init(void *config)
{
    serial_configure_t pt_cfg = config;
    if(config == NULL)
    {
        pt_cfg = &_default_config;
    }
    if(pt_cfg->revbuf_size == 0)
        return -1;
    _revbuf_init(pt_cfg->revbuf_size);
    if((_rev_buf == NULL)||(_rev_buf_size == 0))
        return -1;
    uart_set_ringbuf(0,_rev_buf,_rev_buf_size);
    uart_init(0, pt_cfg->baud_rate, pt_cfg->data_bits, pt_cfg->stop_bits, pt_cfg->parity);
    return 1;
}

static int _ioctl(int cmd, void *arg)
{
    switch(cmd)
    {
        case CMD_REV_INIT:
            uart_rev_init(0);
            break;
        case CMD_GET_REV_POINT:
            *(uint32_t *)arg = (uint32_t)_rev_buf;
            break;
        case CMD_SET_RS485:
            _rs485 = (rs485_mode)arg;
            break;
        default:
            break;
    }
    return 1;
}

static int _readable(void)
{
    return uart_rev_length(0);
}

static uint32_t _read(uint32_t pos, void *buffer, uint32_t size, void *opt)
{
    uint32_t count = 0;
    int r = -1;
    if((buffer == NULL) || (size == 0))
        return 0;

    uint8_t *ptbuf = (uint8_t *)buffer;
    while(count < size)
    {
        r = uart_get_byte(0);
        if(r == -1)
            {break;}
        ptbuf[count] = (uint8_t)r;
        count++;
    }
    return count;
}

static int _writeable(void)
{
    return uart_write_ready(0);
}

static uint32_t _write(uint32_t pos, void *buffer, uint32_t size, void *opt)
{
    if((buffer == NULL) || (size == 0))
        return 0;

    if(_rs485 != NULL){_rs485(RS485_MODE_SEND);}
    uart_send(0,buffer,size);
    if(_rs485 != NULL){_rs485(RS485_MODE_REV);}

    return size;
}

static int _getbyte(void)
{
    return uart_get_byte(0);
}

static SERIAL _serial =
{
    .init = _init,

    .ioctl = _ioctl,
    .read = _read,
    .write = _write,
    .readable = _readable,
    .writeable = _writeable,
    .flush = NULL,

    .getbyte = _getbyte,
};

#define __MODULE_NAME   ("ttyS0")
static void _serial_init(void)
{
    LogDebug("%s start\r\n",__FUNCTION__);
    if(dev_register(__MODULE_NAME, (void *)&_serial) > 0)
    {
        LogInfo("%s ---> ok\r\n",__MODULE_NAME);
    }
}
MODULE_INIT(_serial_init);
